package com.example.setalarm;

import java.util.ArrayList;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.LinearInterpolator;
import android.view.animation.OvershootInterpolator;

import com.example.setalarm.object.BaseIcon;
import com.example.setalarm.utils.Utils;
import com.nineoldandroids.animation.Animator;
import com.nineoldandroids.animation.Animator.AnimatorListener;
import com.nineoldandroids.animation.AnimatorSet;
import com.nineoldandroids.animation.ValueAnimator;
import com.nineoldandroids.animation.ValueAnimator.AnimatorUpdateListener;

public class QuickSelectView extends View {

	public static final int STATE_INVISIBLE = 0;
	public static final int STATE_IN = 1;
	public static final int STATE_VISIBLE = 2;
	public static final int STATE_OUT = 3;

	public interface QuickSelectAppListener {
		public void onAppSelected(int type);
	}

	private Context mContext;
	private GestureDetector mDetector;
	private ArrayList<BaseIcon> mList;

	private float MAX_RADIUS = 100;
	private float mRadius = 25;
	private float screenW, screenH;
	private Paint p;
	private ValueAnimator[] scaleInAnimators, scaleOutAnimators;
	private AnimatorSet scaleInSet, scaleOutSet;
	private float[] scaleValue;
	private ValueAnimator[] scaleIconInAnimator, scaleIconOutAnimator;
	private float[] scaleIconValue;

	private int state;

	private Bitmap bmpCircle;

	private float touchX, touchY;

	private ValueAnimator rotateAnimator;
	private float valueRotate;

	private boolean isFocusIcon;

	private QuickSelectAppListener mAppListener;

	public QuickSelectView(Context context) {
		super(context);
		// TODO Auto-generated constructor stub
		init(context);
	}

	public QuickSelectView(Context context, AttributeSet attrs) {
		super(context, attrs);
		// TODO Auto-generated constructor stub
		init(context);
	}

	private void init(Context context) {
		mContext = context;

		DisplayMetrics metrics = mContext.getResources().getDisplayMetrics();
		MAX_RADIUS = MAX_RADIUS * metrics.density;
		mRadius = mRadius * metrics.density;
		screenW = metrics.widthPixels;
		screenH = metrics.heightPixels;

		mDetector = new GestureDetector(mContext, new MyGestureListener());
		mList = new ArrayList<BaseIcon>();
		for (int i = 0; i < 3; i++)
			mList.add(new BaseIcon(mContext, i + 1, mRadius));

		p = Utils.setPaint();
		p.setColor(Color.WHITE);
		scaleInAnimators = new ValueAnimator[3];
		scaleOutAnimators = new ValueAnimator[3];
		scaleValue = new float[3];

		scaleIconInAnimator = new ValueAnimator[3];
		scaleIconOutAnimator = new ValueAnimator[3];
		scaleIconValue = new float[3];

		bmpCircle = BitmapFactory.decodeResource(mContext.getResources(),
				R.drawable.btn_circle);

		state = STATE_INVISIBLE;
	}

	private void startRotate() {
		if (rotateAnimator == null) {
			rotateAnimator = ValueAnimator.ofFloat(0, 360);
			rotateAnimator.setDuration(1000);
			rotateAnimator.setInterpolator(new LinearInterpolator());
			rotateAnimator.addUpdateListener(new AnimatorUpdateListener() {

				@Override
				public void onAnimationUpdate(ValueAnimator arg0) {
					// TODO Auto-generated method stub
					valueRotate = ((Float) arg0.getAnimatedValue())
							.floatValue();
					invalidate();
				}
			});
			rotateAnimator.setRepeatCount(-1);
		}
		rotateAnimator.start();
	}

	private void pauseRotate() {
		if (rotateAnimator != null)
			rotateAnimator.cancel();
	}

	private void reset() {
		for (int i = 0; i < mList.size(); i++)
			mList.get(i).setState(BaseIcon.STATE_NORMAL);
	}

	private void doActionUp() {

		startScaleOut();
		invalidate();

	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		// TODO Auto-generated method stub
		mDetector.onTouchEvent(event);

		// DebugUtils.d("QuickSelectView", "onTouchEvent:   Kai => " + isShow);
		switch (event.getAction()) {
		case MotionEvent.ACTION_CANCEL:
		case MotionEvent.ACTION_UP:
			doActionUp();
			break;

		case MotionEvent.ACTION_MOVE:
			if (state == STATE_VISIBLE) {
				touchX = event.getX();
				touchY = event.getY();
				checkKiss(event);
				invalidate();
			}
			break;
		case MotionEvent.ACTION_DOWN:
			return true;
		}

		return super.onTouchEvent(event);
	}

	private void checkKiss(MotionEvent ev) {
		for (int i = 0; i < mList.size(); i++)

			if (mList.get(i).isKiss(ev.getX(), ev.getY())) {

				switch (mList.get(i).getState()) {
				case BaseIcon.STATE_NORMAL:
					mList.get(i).setState(BaseIcon.STATE_SCALE_IN);
					startScaleInIcon(i);
					isFocusIcon = true;

					break;

				}

			} else {
				switch (mList.get(i).getState()) {

				case BaseIcon.STATE_SCALE_IN:
					mList.get(i).setState(BaseIcon.STATE_SCALE_OUT);
					startScaleOutIcon(i);
					isFocusIcon = false;
					break;

				}
			}
	}

	private void drawIcon(Canvas canvas, int i, float scale) {

		// canvas.drawCircle(posX, posY, MAX_RADIUS, p);
		canvas.save();
		canvas.scale(scale, scale, posX, posY);

		canvas.drawBitmap(mList.get(i).getBitmap(), mList.get(i).getPos().x,
				mList.get(i).getPos().y, p);

		canvas.restore();
	}

	private void drawIconScale(Canvas canvas, BaseIcon icon, float scale) {

		// canvas.drawCircle(posX, posY, MAX_RADIUS, p);
		canvas.save();
		canvas.scale(scale, scale, icon.getCenter().x, icon.getCenter().y);

		canvas.drawBitmap(icon.getBitmap(), icon.getPos().x, icon.getPos().y, p);

		canvas.restore();
	}

	private void drawCircle(Canvas canvas, float rotate, float x, float y) {
		canvas.save();
		canvas.rotate(rotate, x, y);
		canvas.drawBitmap(bmpCircle, x - bmpCircle.getWidth() / 2, y
				- bmpCircle.getHeight() / 2, p);
		canvas.restore();
	}

	@Override
	protected void onDraw(Canvas canvas) {
		// TODO Auto-generated method stub
		super.onDraw(canvas);

		switch (state) {
		case STATE_INVISIBLE:

			break;

		case STATE_IN:
			drawCircle(canvas, valueRotate, touchX, touchY);
			for (int i = 0; i < mList.size(); i++)
				drawIcon(canvas, i, scaleValue[i]);
			break;
		case STATE_VISIBLE:

			for (int i = 0; i < mList.size(); i++) {
				switch (mList.get(i).getState()) {
				case BaseIcon.STATE_NORMAL:

					drawIcon(canvas, i, 1);
					break;

				case BaseIcon.STATE_SCALE_IN:
					if (isFocusIcon)
						drawCircle(canvas, valueRotate, mList.get(i)
								.getCenter().x, mList.get(i).getCenter().y);

					drawIconScale(canvas, mList.get(i), scaleIconValue[i]);
					// isFocusIcon = true;
					break;

				case BaseIcon.STATE_SCALE_OUT:
					// if (isFocusIcon)
					// drawCircle(canvas, valueRotate, mList.get(i)
					// .getCenter().x, mList.get(i).getCenter().y);

					drawIconScale(canvas, mList.get(i), scaleIconValue[i]);
					break;
				}
			}

			if (!isFocusIcon)
				drawCircle(canvas, valueRotate, touchX, touchY);

			break;
		case STATE_OUT:
			for (int i = 0; i < mList.size(); i++)
				drawIcon(canvas, i, scaleValue[i]);
			break;
		}

	}

	float posX, posY;

	private class MyGestureListener extends
			GestureDetector.SimpleOnGestureListener {

		@Override
		public void onLongPress(MotionEvent e) {
			// TODO Auto-generated method stub
			super.onLongPress(e);
			if (state == STATE_INVISIBLE) {

				startRotate();

				posX = e.getX();
				posY = e.getY();

				touchX = posX;
				touchY = posY;

				if (posY - MAX_RADIUS > 0 && posX + MAX_RADIUS < screenW
						&& posX - MAX_RADIUS > 0) {

					setPos(15, 90, 165);

				} else if (posX + MAX_RADIUS < screenW
						&& posY + MAX_RADIUS < screenH && posY - MAX_RADIUS > 0) {

					setPos(75, 0, 285);
				} else if (posY + MAX_RADIUS < screenH
						&& posX + MAX_RADIUS < screenW && posX - MAX_RADIUS > 0) {

					setPos(345, 270, 195);
				} else if (posX - MAX_RADIUS > 0 && posY + MAX_RADIUS < screenH
						&& posY - MAX_RADIUS > 0) {
					setPos(105, 180, 255);
				}
				invalidate();
			}

		}
	}

	private void setPos(int pos1, int pos2, int pos3) {
		mList.get(2).setPos(caculPoint(posX, posY, MAX_RADIUS, pos1));
		mList.get(0).setPos(caculPoint(posX, posY, MAX_RADIUS, pos2));
		mList.get(1).setPos(caculPoint(posX, posY, MAX_RADIUS, pos3));
		state = STATE_IN;
		startScaleIn();
	}

	private float DEGREE_TO_RADIAN = (float) (2 * Math.PI / 360);

	private Point caculPoint(float px, float py, float radius, int angel) {

		int x = (int) (px + radius * Math.cos(angel * DEGREE_TO_RADIAN));
		int y = (int) (py - radius * Math.sin(angel * DEGREE_TO_RADIAN));
		return new Point(x, y);
	}

	private void startScaleIn() {

		if (scaleInSet == null) {
			for (int i = 0; i < scaleInAnimators.length; i++) {
				initScaleIn(i);
			}
			scaleInSet = new AnimatorSet();
			scaleInSet.playTogether(scaleInAnimators);
			scaleInSet.addListener(new AnimatorListener() {

				@Override
				public void onAnimationStart(Animator arg0) {
					// TODO Auto-generated method stub

				}

				@Override
				public void onAnimationRepeat(Animator arg0) {
					// TODO Auto-generated method stub

				}

				@Override
				public void onAnimationEnd(Animator arg0) {
					// TODO Auto-generated method stub
					state = STATE_VISIBLE;
				}

				@Override
				public void onAnimationCancel(Animator arg0) {
					// TODO Auto-generated method stub

				}
			});

		}

		for (int i = 0; i < scaleValue.length; i++)
			scaleValue[i] = 0;

		scaleInSet.start();
	}

	private void initScaleIn(final int index) {
		if (scaleInAnimators[index] == null) {
			scaleInAnimators[index] = ValueAnimator.ofFloat(0, 1);
			scaleInAnimators[index]
					.addUpdateListener(new AnimatorUpdateListener() {

						@Override
						public void onAnimationUpdate(ValueAnimator animation) {
							// TODO Auto-generated method stub
							scaleValue[index] = ((Float) animation
									.getAnimatedValue()).floatValue();
							invalidate();
						}
					});

			scaleInAnimators[index].setDuration(300);
			scaleInAnimators[index].setStartDelay(index * 100);
			scaleInAnimators[index]
					.setInterpolator(new OvershootInterpolator());
		}

	}

	private void startScaleOut() {

		if (scaleInSet != null && scaleInSet.isRunning())
			scaleInSet.cancel();
		state = STATE_OUT;
		if (scaleOutSet == null) {
			for (int i = 0; i < scaleOutAnimators.length; i++) {
				initScaleOut(i);
			}
			scaleOutSet = new AnimatorSet();
			scaleOutSet.playTogether(scaleOutAnimators);
			scaleOutSet.addListener(new AnimatorListener() {

				@Override
				public void onAnimationStart(Animator arg0) {
					// TODO Auto-generated method stub

				}

				@Override
				public void onAnimationRepeat(Animator arg0) {
					// TODO Auto-generated method stub

				}

				@Override
				public void onAnimationEnd(Animator arg0) {
					// TODO Auto-generated method stub
					state = STATE_INVISIBLE;
					pauseRotate();
					isFocusIcon = false;
					if (isFocusIcon)
						for (int i = 0; i < mList.size(); i++)
							if (mList.get(i).getState() == BaseIcon.STATE_SCALE_IN)
								if (mAppListener != null)
									mAppListener.onAppSelected(mList.get(i)
											.getType());
					reset();
				}

				@Override
				public void onAnimationCancel(Animator arg0) {
					// TODO Auto-generated method stub

				}
			});

		}

		scaleOutSet.start();
	}

	private void initScaleOut(final int index) {
		if (scaleOutAnimators[index] == null) {
			scaleOutAnimators[index] = ValueAnimator.ofFloat(1, 0);
			scaleOutAnimators[index]
					.addUpdateListener(new AnimatorUpdateListener() {

						@Override
						public void onAnimationUpdate(ValueAnimator animation) {
							// TODO Auto-generated method stub
							scaleValue[index] = ((Float) animation
									.getAnimatedValue()).floatValue();
							invalidate();
						}
					});

			scaleOutAnimators[index].setDuration(300);
			scaleOutAnimators[index].setStartDelay(index * 100);
			scaleOutAnimators[index]
					.setInterpolator(new OvershootInterpolator());
		}

	}

	private void startScaleInIcon(final int index) {
		if (scaleIconInAnimator[index] == null) {
			scaleIconInAnimator[index] = ValueAnimator.ofFloat(1, 1.3f);
			scaleIconInAnimator[index].setDuration(300);
			scaleIconInAnimator[index]
					.setInterpolator(new OvershootInterpolator());
			scaleIconInAnimator[index]
					.addUpdateListener(new AnimatorUpdateListener() {

						@Override
						public void onAnimationUpdate(ValueAnimator arg0) {
							// TODO Auto-generated method stub
							scaleIconValue[index] = ((Float) arg0
									.getAnimatedValue()).floatValue();
							invalidate();
						}
					});
		}
		scaleIconInAnimator[index].start();
	}

	private void startScaleOutIcon(final int index) {
		if (scaleIconOutAnimator[index] == null) {
			scaleIconOutAnimator[index] = ValueAnimator.ofFloat(1.3f, 1);
			scaleIconOutAnimator[index].setDuration(300);
			scaleIconOutAnimator[index]
					.setInterpolator(new OvershootInterpolator());
			scaleIconOutAnimator[index]
					.addUpdateListener(new AnimatorUpdateListener() {

						@Override
						public void onAnimationUpdate(ValueAnimator arg0) {
							// TODO Auto-generated method stub
							scaleIconValue[index] = ((Float) arg0
									.getAnimatedValue()).floatValue();
							invalidate();
						}
					});
			scaleIconOutAnimator[index].addListener(new AnimatorListener() {

				@Override
				public void onAnimationStart(Animator arg0) {
					// TODO Auto-generated method stub

				}

				@Override
				public void onAnimationRepeat(Animator arg0) {
					// TODO Auto-generated method stub

				}

				@Override
				public void onAnimationEnd(Animator arg0) {
					// TODO Auto-generated method stub
					mList.get(index).setState(BaseIcon.STATE_NORMAL);

				}

				@Override
				public void onAnimationCancel(Animator arg0) {
					// TODO Auto-generated method stub

				}
			});
		}
		scaleIconOutAnimator[index].start();
	}

	public QuickSelectAppListener getmAppListener() {
		return mAppListener;
	}

	public void setmAppListener(QuickSelectAppListener mAppListener) {
		this.mAppListener = mAppListener;
	}

}
